package com.siao.component
{
	import com.siao.data.ArrayList;
	import com.siao.display.LayoutElement;
	import com.siao.events.DataChangeEvent;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	/**
	 * 列表组件
	 * @author SiaoLeon
	 */
	public class List extends LayoutElement implements ISelector
	{
		// -------------------------------------------------------------------------------------------------------- 静态常量
		
		// -------------------------------------------------------------------------------------------------------- 静态变量
		
		// -------------------------------------------------------------------------------------------------------- 静态方法
		
		// -------------------------------------------------------------------------------------------------------- 静态函数
		
		// -------------------------------------------------------------------------------------------------------- 属性
		
		private var _selected:*;
		
		public function get selected():*
		{
			return this._selected;
		}
		
		public function set selected(value:*):void
		{
			this._selected = value;
			
			for each (var item:IDataItem in this.list)
			{
				if (!(item is ISelectItem))
				{
					continue;
				}
				
				(item as ISelectItem).selected = (this.selected == item.data || ((this.selected is ArrayList) && (this.selected as ArrayList).contains(item.data)));
			}
		}
		
		private var _width:Number;
		
		override public function set width(value:Number):void
		{
			this._width = super.width = value;;
		}
		
		private var _height:Number;
		
		override public function set height(value:Number):void
		{
			this._height = super.height = value;;
		}
		
		/**
		 * 是否允许多选，设置此选项为true时将允许用户按住Ctrl键进行多选
		 * @default false
		 */
		public var multiSelected:Boolean;
		
		private var _cancelMode:Boolean;
		
		/**
		 * 是否支持可取消选择，不可取消时将默认选择数据列表中的首数据，可取消时点击舞台其他区域将取消选择
		 * @return
		 */
		public function get cancelMode():Boolean
		{
			return this._cancelMode;
		}
		
		public function set cancelMode(value:Boolean):void
		{
			this._cancelMode = value;
			
			if (!this.cancelMode && this.selected == null && this.data != null && this.data.length > 0)
			{
				this.selected = this.data.element(0);
			}
			
			this.registerEventListeners();
		}
		
		private var _itemClass:Class;
		
		/**
		 * 项目类型，该类型必须继承IDataItem接口，并是DisplayObject的子类
		 * @return
		 */
		public function get itemClass():Class
		{
			return this._itemClass;
		}
		
		public function set itemClass(value:Class):void
		{
			this._itemClass = value;
			
			this.bind(this.itemClass, this.data);
		}
		
		private var _data:ArrayList;
		
		/**
		 * 列表数据
		 * @return
		 */
		public function get data():ArrayList
		{
			return this._data;
		}
		
		public function set data(value:ArrayList):void
		{
			this._data = value;
			
			this.bind(this.itemClass, this.data);
		}
		
		private var _orientation:uint;
		
		/**
		 * 排列方式
		 * @return
		 */
		public function get orientation():uint
		{
			return this._orientation;
		}
		
		public function set orientation(value:uint):void
		{
			this._orientation = (value > Orientation.BOTTOM_TOP) ? value & 1 : value;
			
			this.arrange();
		}
		
		private var _wrapOrientation:uint;
		
		/**
		 * 换行方式
		 * @return
		 */
		public function get wrapOrientation():uint
		{
			return this._wrapOrientation;
		}
		
		public function set wrapOrientation(value:uint):void
		{
			this._wrapOrientation = (value > Orientation.BOTTOM_TOP) ? value & 1 : value;
			
			this.arrange();
		}
		
		private var _wrap:Boolean
		
		/**
		 * 是否自动换行
		 * @return
		 */
		public function get wrap():Boolean
		{
			return this._wrap;
		}
		
		public function set wrap(value:Boolean):void
		{
			this._wrap = value;
			
			this.arrange();
		}
		
		private var _rowSpacing:Number = 0;
		
		/**
		 * 行间距
		 * @return
		 */
		public function get rowSpacing():Number
		{
			return this._rowSpacing;
		}
		
		public function set rowSpacing(value:Number):void
		{
			this._rowSpacing = value;
			
			this.arrange();
		}
		
		private var _colSpacing:Number = 0;
		
		/**
		 * 列间距
		 * @return
		 */
		public function get colSpacing():Number
		{
			return this._colSpacing;
		}
		
		public function set colSpacing(value:Number):void
		{
			this._colSpacing = value;
			
			this.arrange();
		}
		
		private var _itemWidth:Number;
		
		/**
		 * 项目宽度
		 * @return
		 */
		public function get itemWidth():Number
		{
			return this._itemWidth;
		}
		
		private var _itemHeight:Number;
		
		/**
		 * 项目高度
		 * @return
		 */
		public function get itemHeight():Number
		{
			return this._itemHeight;
		}
		
		private var _itemMaxWidth:Number;
		
		/**
		 * 项目最大宽度（仅当项目为LayoutElement时可用）
		 * @return
		 */
		public function get itemMaxWidth():Number
		{
			return this._itemMaxWidth;
		}
		
		private var _itemMaxHeight:Number;
		
		/**
		 * 项目最大高度（仅当项目为LayoutElement时可用）
		 * @return
		 */
		public function get itemMaxHeight():Number
		{
			return this._itemMaxHeight;
		}
		
		private var _row:uint;
		
		/**
		 * 行数
		 * @return
		 */
		public function get row():uint
		{
			return this._row;
		}
		
		private var _col:uint;
		
		/**
		 * 列数
		 * @return
		 */
		public function get col():uint
		{
			return this._col;
		}
		
		// -------------------------------------------------------------------------------------------------------- 变量
		
		private var list:Array = new Array();
		
		// -------------------------------------------------------------------------------------------------------- 构造
		
		/**
		 * 构造函数
		 * @param orientation 排列方向
		 * @param wrapOrientation 换行方向（当换行可用时）
		 */
		public function List(orientation:uint=Orientation.TOP_BOTTOM, wrapOrientation:uint=Orientation.LEFT_RIGHT)
		{
			super();
			
			this._orientation = (orientation > Orientation.RIGHT_LEFT) ? orientation & 1 : orientation;
			this._wrapOrientation = (wrapOrientation > Orientation.RIGHT_LEFT) ? wrapOrientation & 1 : wrapOrientation;
		}
		
		// -------------------------------------------------------------------------------------------------------- 方法
		
		override public function clear():void
		{
			super.clear();
			
			for each (var item:DisplayObject in this.list)
			{
				item.removeEventListener(MouseEvent.CLICK, onClick);
			}
			
			if (this.data != null)
			{
				this.data.removeEventListener(DataChangeEvent.CHANGE, onDataChange);
			}
			
			this.list = null;
			this._itemClass = null;
			this._data = null;
			this._row = this._col = 0;
			this._itemWidth = this._itemHeight = this._itemMaxWidth = this._itemMaxHeight = Number.NaN;
		}
		
		override public function resize():void
		{
			super.resize();
			
			this.arrange();
		}
		
		/**
		 * 绑定数据
		 * @param itemClass 项目类型，该类型必须继承IDataItem接口，并是DisplayObject的子类
		 * @param data 列表数据
		 */
		public function bind(itemClass:Class, data:ArrayList):void
		{
			this.clear();
			
			this._itemClass = (itemClass == null) ? this.itemClass : itemClass;
			this._data = (data == null) ? this.data : data;
			
			if (this.data == null || this.itemClass == null)
			{
				return;
			}
			
			this.list = new Array();
			
			for each (var info:* in this.data.toArray())
			{
				var item:IDataItem = new itemClass();
				
				if (item is IListItem)
				{
					(item as IListItem).index = this.data.indexOf(info);
				}
				
				item.data = info;
				this.list.push(item);
				
				this._itemWidth = (item as DisplayObject).width;
				this._itemHeight = (item as DisplayObject).height;
				
				if (item is LayoutElement)
				{
					this._itemMaxWidth = (item as LayoutElement).maxWidth;
					this._itemMaxHeight = (item as LayoutElement).maxHeight;
				}
			}
			
			this.data.addEventListener(DataChangeEvent.CHANGE, onDataChange, false, 0, true);
			
			this.arrange();
			
			if (!this.cancelMode && this.selected == null)
			{
				this.selected = this.data.element(0);
			}
		}
		
		// -------------------------------------------------------------------------------------------------------- 函数
		
		override protected final function init():void
		{
			//仅在显示时初始化布局
			if (this.stage == null || !this.visible)
			{
				return;
			}
			
			super.init();
			
			this.registerEventListeners();
		}
		
		override protected final function exit():void
		{
			super.exit();
			
			this.removeEventListeners();
		}
		
		/**
		 * 注册事件侦听
		 */
		protected function registerEventListeners():void
		{
			if (this.stage != null)
			{
				if (this.cancelMode)
				{
					this.stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown, false, 0, true);
				}
				else
				{
					this.stage.removeEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
				}
			}
		}
		
		/**
		 * 移除事件侦听
		 */
		protected function removeEventListeners():void
		{
			if (this.stage != null)
			{
				this.stage.removeEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
			}
		}
		
		/**
		 * 布局列表内项目
		 */
		private function arrange():void
		{
			if (this.stage == null || !this.visible)
			{
				return;
			}
			
			var showWidth:Number = this.width - this.paddingLeft - this.paddingRight;
			var showHeight:Number = this.height - this.paddingTop - this.paddingBottom;
			
			//计算行列数
			switch (this.orientation)
			{
				case Orientation.HORIZONTAL:
				case Orientation.LEFT_RIGHT:
				case Orientation.RIGHT_LEFT:
					
					if (this.wrap)
					{
						if (this.itemWidth == 0)
						{
							if (isNaN(this.itemMaxWidth) || showWidth < (this.itemMaxWidth + this.colSpacing) * Math.ceil(Math.sqrt(this.list.length)) - this.colSpacing)
							{
								this._col = Math.max(1, Math.ceil(Math.sqrt(this.list.length)));
							}
							else
							{
								this._col = Math.max(1, Math.floor(showWidth + this.colSpacing) / (this.itemMaxWidth + this.colSpacing));
							}
						}
						else
						{
							this._col = Math.max(1, Math.floor(showWidth + this.colSpacing) / (this.itemWidth + this.colSpacing));
						}
					}
					else
					{
						this._col = Math.max(1, this.list.length);
					}
					
					this._row = Math.max(1, Math.ceil(this.list.length / this.col));
					
					break;
				
				case Orientation.VERTICAL:
				case Orientation.TOP_BOTTOM:
				case Orientation.BOTTOM_TOP:
					
					if (this.wrap)
					{
						if (this.itemHeight == 0)
						{
							if (isNaN(this.itemMaxHeight) || showHeight < (this.itemMaxHeight + this.rowSpacing) * Math.ceil(Math.sqrt(this.list.length)) - this.rowSpacing)
							{
								this._row = Math.max(1, Math.ceil(Math.sqrt(this.list.length)));
							}
							else
							{
								this._row = Math.max(1, Math.floor(showHeight + this.rowSpacing) / (this.itemMaxHeight + this.rowSpacing));
							}
						}
						else
						{
							this._row = Math.max(1, Math.floor(showHeight + this.rowSpacing) / (this.itemHeight + this.rowSpacing));
						}
					}
					else
					{
						this._row = Math.max(1, this.list.length);
					}
					
					this._col = Math.max(1, Math.ceil(this.list.length / this.row));
					
					break;
			}
			
			//计算每个项目的尺寸、位置
			for each (var item:DisplayObject in this.list)
			{
				//计算项目尺寸
				if (this.itemWidth == 0)
				{
					item.width = Math.max(0, (showWidth + this.colSpacing) / this.col - this.colSpacing);
				}
				
				if (this.itemHeight == 0)
				{
					item.height = Math.max(0, (showHeight + this.rowSpacing) / this.row - this.rowSpacing);
				}
				
				//获取项目所在行、列
				var itemRow:uint = 0;
				var itemCol:uint = 0;
				
				switch (this.orientation)
				{
					case Orientation.HORIZONTAL:
					case Orientation.LEFT_RIGHT:
						itemCol = (this.list.indexOf(item) + 1) % this.col;
						itemCol = (itemCol == 0) ? this.col : itemCol;
						itemRow = (this.wrapOrientation == Orientation.BOTTOM_TOP) ? this.row - Math.floor(this.list.indexOf(item) / this.col) : Math.ceil((this.list.indexOf(item) + 1) / this.col);
						break;
					case Orientation.RIGHT_LEFT:
						itemCol = this.col - this.list.indexOf(item) % this.col;
						itemRow = (this.wrapOrientation == Orientation.BOTTOM_TOP) ? this.row - Math.floor(this.list.indexOf(item) / this.col) : Math.ceil((this.list.indexOf(item) + 1) / this.col);
						break;
					
					case Orientation.VERTICAL:
					case Orientation.TOP_BOTTOM:
						itemRow = (this.list.indexOf(item) + 1) % this.row;
						itemRow = (itemRow == 0) ? this.row : itemRow;
						itemCol = (this.wrapOrientation == Orientation.RIGHT_LEFT) ? this.col - Math.floor(this.list.indexOf(item) / this.row) : Math.ceil((this.list.indexOf(item) + 1) / this.row);
						break;
					case Orientation.BOTTOM_TOP:
						itemRow = this.row - this.list.indexOf(item) % this.row;
						itemCol = (this.wrapOrientation == Orientation.RIGHT_LEFT) ? this.col - Math.floor(this.list.indexOf(item) / this.row) : Math.ceil((this.list.indexOf(item) + 1) / this.row);
						break;
				}
				
				//根据项目所在行列定位坐标
				item.x = (itemCol - 1) * (item.width + this.colSpacing);
				item.y = (itemRow - 1) * (item.height + this.rowSpacing);
				
				if (this.orientation == Orientation.RIGHT_LEFT || this.wrapOrientation == Orientation.RIGHT_LEFT)
				{
					item.x += this.width - this.paddingRight - this.col * (item.width + this.colSpacing) - this.colSpacing;
				}
				
				if (this.orientation == Orientation.BOTTOM_TOP || this.wrapOrientation == Orientation.BOTTOM_TOP)
				{
					item.y += this.height - this.paddingBottom - this.row * (item.height + this.rowSpacing) - this.rowSpacing;
				}
				
				item.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
				this.addChild(item);
			}
			
			if (isNaN(this._width))
			{
				this.range.width = this.col * (this.itemWidth + this.colSpacing) - this.colSpacing;
			}
			
			if (isNaN(this._height))
			{
				this.range.height = this.row * (this.itemHeight + this.rowSpacing) - this.rowSpacing;
			}
		}
		
		/**
		 * 数据变更时
		 */
		private function onDataChange(event:Event):void
		{
			this.bind(this.itemClass, this.data);
		}
		
		/**
		 * 舞台鼠标按下时
		 * @param event
		 */
		private function onStageMouseDown(event:MouseEvent):void
		{
			var array:Array = this.stage.getObjectsUnderPoint(new Point(this.stage.mouseX, this.stage.mouseY));
			
			if (array.indexOf(this) < 0)
			{
				this.selected = null;
			}
		}
		
		/**
		 * 鼠标点击时
		 * @param event
		 */
		private function onClick(event:MouseEvent):void
		{
			var clickData:* = (event.currentTarget as IDataItem).data;
			
			if (this.multiSelected && event.ctrlKey)
			{
				//按住Ctrl多选
				if (this.selected is ArrayList)
				{
					//当前选择是列表
					if (!(this.selected as ArrayList).contains(clickData))
					{
						//所选数据不在已选列表中
						this.selected = (this.selected as ArrayList).concat(new Array(clickData));
					}
					else
					{
						//可取消模式，或不是唯一数据
						if (this.cancelMode || (this.selected as ArrayList).length > 1)
						{
							(this.selected as ArrayList).remove(clickData);
							this.selected = this.selected;
						}
					}
				}
				else
				{
					//当前选择不是列表
					this.selected = (this.selected == null) ? new ArrayList(clickData) : (this.selected is ArrayList) ? (this.selected as ArrayList).concat(new Array(clickData)) : new ArrayList(this.selected, clickData);
				}
			}
			else
			{
				//直接点击单选
				if (this.cancelMode && this.selected == clickData)
				{
					//可取消模式，并且点击当前选择
					this.selected = null;
				}
				
				if (this.selected != clickData)
				{
					//点击与当前选择不一致
					this.selected = clickData;
				}
				
				this.dispatchEvent(new Event(Event.SELECT));
			}
		}
	
	}
}
